/*
 * BinaryExpression.java
 * 
 * last update: 15.01.2010 by Stefan Saru
 * 
 * author:	Power
 *
 * Obs:  
 */
package engine;

/**
 * It is is something like x 'op' y, where x and y are also expressions
 * the evaluate() assigns x <- x 'op' y
 */
class BinaryExpression extends Expression {

	final static int LOGICAL_OR           = 0;
	final static int LOGICAL_AND          = 1;
	final static int BITWISE_OR           = 2;
	final static int BITWISE_NOR          = 3;
	final static int BITWISE_AND          = 4;
	final static int BITWISE_NAND         = 5;
	final static int BITWISE_XOR          = 6;
	final static int BITWISE_NXOR         = 7;
	final static int LOGICAL_EQUALITY     = 8;
	final static int LOGICAL_NONEQUALITY  = 9;
	final static int CASE_EQUALITY        = 10;
	final static int CASE_NONEQUALITY     = 11;
	final static int LESS_THAN            = 12;
	final static int LESS_OR_EQUAL        = 13;
	final static int GREATER_THAN         = 14;
	final static int GREATER_OR_EQUAL     = 15;
	final static int LEFT_SHIFT           = 16;
	final static int RIGHT_SHIFT          = 17;
	final static int ADDITION             = 18;
	final static int SUBSTRACTION         = 19;
	final static int MULTIPLICATION       = 20;
	final static int DIVISION             = 21;
	final static int MODULUS              = 22;

	public static String[] opStrings = {" || ", " && ", " | ", " ~| ", " & ", " ~& ",
		" ^ ", " ~^ ", " == ", " != ", " === ", " !== ",
		" < ", " <= ", " > ", " >= ", " << ", " >> ",
		" + ", " - ", " * ", " / ", " % "};

	Expression left, right;
	int op = 0;
	NameSpace ns;

	BinaryExpression(NameSpace ns, Expression l, String oper, Expression r) throws ParseException{
		super(ns);
		left = l;
		right = r;
		if (oper.equals("||")) op = LOGICAL_OR;
		else if (oper.equals("&&")) op = LOGICAL_AND;
		else if (oper.equals("|")) op = BITWISE_OR;
		else if (oper.equals("~|")) op = BITWISE_NOR;
		else if (oper.equals("&")) op = BITWISE_AND;
		else if (oper.equals("~&")) op = BITWISE_NAND;
		else if (oper.equals("^")) op = BITWISE_XOR;
		else if (oper.equals("~&")) op = BITWISE_NXOR;
		else if (oper.equals("==")) op = LOGICAL_EQUALITY;
		else if (oper.equals("!=")) op = LOGICAL_NONEQUALITY;
		else if (oper.equals("===")) op = CASE_EQUALITY;
		else if (oper.equals("!==")) op = CASE_NONEQUALITY;
		else if (oper.equals("<")) op = LESS_THAN;
		else if (oper.equals("<=")) op = LESS_OR_EQUAL;
		else if (oper.equals(">")) op = GREATER_THAN;
		else if (oper.equals(">=")) op = GREATER_OR_EQUAL;
		else if (oper.equals("<<")) op = LEFT_SHIFT;
		else if (oper.equals(">>")) op = RIGHT_SHIFT;
		else if (oper.equals("+")) op = ADDITION;
		else if (oper.equals("-")) op = SUBSTRACTION;
		else if (oper.equals("*")) op = MULTIPLICATION;
		else if (oper.equals("/")) op = DIVISION;
		else if (oper.equals("%")) op = MODULUS;
		else throw new Error("BinaryExpression.<init> : unknown operator allowed by paraser ?? : " + oper);

		switch (op){
		case LOGICAL_EQUALITY:
		case LOGICAL_NONEQUALITY:
		case CASE_EQUALITY:
		case CASE_NONEQUALITY:
		case LESS_THAN:
		case LESS_OR_EQUAL:
		case GREATER_THAN:
		case GREATER_OR_EQUAL:
		case LOGICAL_OR:
		case LOGICAL_AND:
			length = 1;
			break;

		case BITWISE_OR:
		case BITWISE_NOR:
		case BITWISE_AND:

		case BITWISE_NAND:
		case BITWISE_XOR:
		case BITWISE_NXOR:
		case ADDITION:
		case DIVISION:
		case MODULUS:
		case SUBSTRACTION:
			length = left.length >= right.length ? left.length : right.length;
			break;

		case LEFT_SHIFT:
		case RIGHT_SHIFT:
			length = left.length;
			break;

		case MULTIPLICATION:
			length = left.length + right.length;
			break;

		default: 
			throw new Error("BinaryExpression.<init> : unknown operator  allowed by parser ??:" + op);
		}


	}


	public Result evaluate()
	throws InterpretTimeException
	{
		Result lVal = left.evaluate(),
		rVal = right.evaluate();

		switch (op){

		case LOGICAL_EQUALITY:
			return lVal.lEq(rVal);

		case LOGICAL_NONEQUALITY:
			return lVal.lNEq(rVal);

		case BITWISE_OR:
			lVal.bOr(rVal);
			break;

		case LOGICAL_OR:
			switch(lVal.getBool() | rVal.getBool()){

			case BitVector.X:
			case BitVector.Z:
				return BitVector.bX();

			case 0: return BitVector.b0();

			case 1: return BitVector.b1();

			}

		case BITWISE_NOR:
			lVal.bNOr(rVal);
			break;

		case BITWISE_AND:
			lVal.bAnd(rVal);
			break;

		case LOGICAL_AND:
			int l = lVal.getBool(),
			r = rVal.getBool();
			switch(l | r){
			case BitVector.X:
			case BitVector.Z: return BitVector.bX();
			default: return (l & r) != 0 ? BitVector.b1() : BitVector.b0();
			}

		case BITWISE_NAND:
			lVal.bNAnd(rVal);
			break;

		case BITWISE_XOR:
			lVal.bXor(rVal);
			break;

		case BITWISE_NXOR:
			lVal.bNXor(rVal);
			break;

		case CASE_EQUALITY:
			return lVal.cEq(rVal);
		case CASE_NONEQUALITY:
			return lVal.cNEq(rVal);

		case LESS_THAN:
			return lVal.lt(rVal);

		case LESS_OR_EQUAL:
			return lVal.le(rVal);

		case GREATER_THAN:
			return lVal.gt(rVal);

		case GREATER_OR_EQUAL:
			return lVal.ge(rVal);

		case LEFT_SHIFT:
			lVal.shl(rVal);
			break;

		case RIGHT_SHIFT:
			lVal.shr(rVal);
			break;

		case ADDITION:
			return lVal.add(rVal);

		case SUBSTRACTION:
			return lVal.sub(rVal);

		case MULTIPLICATION:
			return lVal.mul(rVal);

		case DIVISION:
			return lVal.div(rVal);

		case MODULUS:
			lVal.mod(rVal);
			break;

		default: 
			throw new Error("BinaryExpression.evaluate : unknown operator !");
		}
		return lVal;
	}

	void addMonitor(Monitor m){
		left.addMonitor(m);
		right.addMonitor(m);
	}

	public boolean isLeftValue(){
		return false;
	}

	public String toString(){
		return left + opStrings[op] + right;
	}
}

